#include <sstream>
#include "PluginManager.h"

PluginManager* PluginManager::_instance = NULL;
char PluginManager::dllFolder[] = "src/PluginDLLs/*.dll";

PluginManager::PluginManager()
{
	//load all plugins from the pluginDLLs folder to _pluginsDLL
	WIN32_FIND_DATA FindFileData;
	HANDLE hFind = FindFirstFile(dllFolder, &FindFileData);
	if (hFind != INVALID_HANDLE_VALUE)
	{
		do
		{
			if((strcmp(FindFileData.cFileName, ".") != 0) && (strcmp(FindFileData.cFileName, "..")  != 0) )
			{
				std::stringstream ss;
				ss << FindFileData.cFileName;
				std::string a;
				ss >> a;
				std::string b = "src/PluginDLLs/" + a;
				_pluginsDLL.push_back(b.c_str());
			}
		}while (FindNextFile(hFind, &FindFileData) != 0);
		FindClose(hFind);
	}
	
}

PluginManager::~PluginManager()
{
}

PluginManager * PluginManager::Instance()
{
	return _instance;
}

void PluginManager::create()
{
	if (_instance == NULL)
	{
		_instance = new PluginManager();		
	}
}

void PluginManager::destroy()
{
	delete _instance;
	_instance = NULL;
}

void PluginManager::loadAllPlugins()
{
	//LoadLibrary(name) in each dll found by traversing _pluginsDLL
	std::vector<std::string>::iterator it;
	for(it=_pluginsDLL.begin() ; it != _pluginsDLL.end(); ++it) 
	{
		HMODULE hmod = loadPlugin(*it);
		if(hmod!=NULL)
		{
			_pluginsHandler.push_back(hmod);
		}
	}
	std::vector<HMODULE>::iterator it1;
	for(it1=_pluginsHandler.begin() ; it1 != _pluginsHandler.end(); ++it1) 
	{
		//createplugin
		PCREATEFUNC pfunc = (PCREATEFUNC)::GetProcAddress(*it1,"createPlugin");
		if(pfunc!=NULL)
		{
			_plugins.push_back(pfunc(*PluginManager::Instance()));
		}
	}
}

void PluginManager::unloadAllPlugins()
{
	std::vector<Plugin *>::iterator it;
	for(it=_plugins.begin() ; it != _plugins.end(); ++it) 
	{
		delete *it;
	}
	_plugins.clear();

	std::vector<HMODULE>::iterator it1;
	for(it1=_pluginsHandler.begin() ; it1 != _pluginsHandler.end(); ++it1) 
	{
		FreeLibrary(*it1);
	}
	_pluginsHandler.clear();
}

Plugin * PluginManager::getPlugins(std::string pluginName)
{
	std::vector<Plugin *>::iterator it;
	for(it=_plugins.begin() ; it != _plugins.end(); ++it) 
	{
		if((*it)->getPluginName().compare(pluginName) == 0)
		{
			return *it;
		}
	}
	return NULL;
}

HMODULE PluginManager::loadPlugin(std::string dllName)
{
	HMODULE hmod = LoadLibrary(dllName.c_str());
	return hmod;
}

void  PluginManager::setPluginsDLLFolderName(std::string dllFolderName)
{
	//set the name of th plugins(dlls) folder
	if((unsigned)strlen(dllFolder) >= dllFolderName.size())
	{
		strcpy(dllFolder, dllFolderName.c_str());
	}else{
		memset (dllFolder,' ',(dllFolderName.size()-(unsigned)strlen(dllFolder)));
		strcpy(dllFolder, dllFolderName.c_str());
	}

}

std::string PluginManager::getPluginsDLLFolderName() const
{
	//return the dllFolder as a string
	std::stringstream ss;
	ss << dllFolder;
	std::string a;
	ss >> a;
	return a;
}